#include "def.h"
#include "gui.h"
#include "plugin.h"
#include "sync.h"
#include "net.h"
#include "util.h"
#include "main.h"	//For mfnplugin
#include <stdio.h>

#pragma message ("remove when VTRY/VCATCH refactored")
#include "..\Global\globaldef.h"
#include "..\CommLib\PacketConven.h"

#include <maya/MGlobal.h>
#include <maya/MFnDagNode.h>
#include <maya/MCallbackIdArray.h>

void VGUI::UserInteractionHandler::MessageHandler(const MArgList& args) {

	uint argCount = args.length();
	if(argCount <= 1)
		return;
	
	MString functionID = args.asString(0);

	if(functionID == "AddressSelected") {

		VNet::HostAddress = args.asString(1);
		return;
	}
	
	if(functionID == "Connect") {

		if(VNet::IsConnected()) {

			if(VNet::Disconnect())
				VNet::Connect();
		} 
		else
			VNet::Connect();

		VGUI::Refresh::ViewServer();
		return;
	}
	
	if(functionID == "Disconnect") {
		
		VNet::Disconnect();
		VGUI::Refresh::ViewServer();
		return;
	}

	if(functionID == "SendData") {

		MString objectName = args.asString(1);
		int syncFlag = args.asString(2).asInt();

		MObject targetObject;
		if(!VUtil::GetMeshByName(objectName, targetObject))
			return;

		if(syncFlag & 0x1) {
			VNet::SendSamplers(targetObject);
		}
		if(syncFlag & 0x2) {
			VNet::SendInstancing(targetObject);
		}
		if(syncFlag & 0x8) {
			VNet::SendParameters(targetObject);
		}
		if(syncFlag & 0x10) {
			VNet::SendDeformation(targetObject);
		}
	}

	if(functionID == "lvCreateSampler") {

		/*MString objectName = args.asString(1);
		MString objectChannel = args.asString(2);
		*/
		MString samplerName = args.asString(3);
		MObject samplerObject;
		if(VUtil::GetSurfaceTextureByName(samplerName, samplerObject)) {
		
			VSyncViewer::AddSamplerCallback(samplerObject);
		}
	}

}

bool VGUI::Initialize() {

	VTRY {
			
		MObject pluginObject;
		if(!VPlugin::GetPlugin(pluginObject))
			VTHROW_INTERNALERROR("Failed to get plugin object.");

		MFnPlugin plugin(pluginObject);

		//Forces the mel gui script to reload
		//Useful for debugging/development
		if(MAYA_FAIL(MGlobal::executeCommand("source lvUtilities.mel; source lvEvents.mel; source lvInit.mel", false, false)))
			VTHROW_INTERNALERROR("Failed to update GUI create script.");

		if(MAYA_FAIL(MGlobal::executeCommand("source lvShutdown.mel", false, false)))
			VTHROW_INTERNALERROR("Failed to update GUI release script.");

		if(MAYA_FAIL(plugin.registerUI("lvInit", "lvShutdown")))
			VTHROW_INTERNALERROR("Failed to register GUI");

		if(MAYA_FAIL(plugin.registerCommand( "CallFunction", VGUI::UserInteractionHandler::Instantiate )))
			VTHROW_INTERNALERROR("Failed to register GUI command");

		return true;
	}
	VCATCH;

	VGUI::Release();
	return false;
}

bool VGUI::Release() {

	VTRY {

		MObject pluginObject;
		if(!VPlugin::GetPlugin(pluginObject))
			VTHROW_INTERNALERROR("Failed to get plugin object.");

		MFnPlugin plugin(pluginObject);
		if(MAYA_FAIL(plugin.deregisterCommand("CallFunction")))
			VTHROW_INTERNALERROR("Failed to deregister interface command.");
	
		return true;
	}
	VCATCH;

	return false;
}

bool VGUI::Refresh::Interface() {

	bool result = true;

	result &= VGUI::Refresh::ViewServer();
	result &= VGUI::Refresh::CurrentSelection();
	result &= VGUI::Refresh::SelectionParameters();
	result &= VGUI::Refresh::ProceduralPopulation();
	result &= VGUI::Refresh::DeformationParameters();

	return result;
}

/**
	Updates components on the deformation panel
	
	@author Dacre Denny
	@return true if successful, false otherwise
*/
bool VGUI::Refresh::DeformationParameters() {
	
	MString parameterString;

	if(VSyncViewer::Selection::IsValid()) {

		MStatus result;
		MFnDagNode meshDN(VSyncViewer::Selection::Mesh, &result);
		MAYA_RETURN_IF_FAIL(result, false);
		
		parameterString = meshDN.name();
	}
	else {

		parameterString = "";
	}

	MString commandString = "UpdateDeformationPanel(" + MAYA_STRINGSTRING( parameterString ) + ");";
	MAYA_RETURN_IF_FAIL(MGlobal::executeCommand(commandString, false, false), false);
	return true;

}

/**
	Updates components on the connection panel
	
	@author Dacre Denny
	@return true if successful, false otherwise
*/
bool VGUI::Refresh::ViewServer() {
	
	MString command = "UpdateConnectionPanel(\"" + VNet::Status() + "\"," + (VNet::IsConnected() ? "1" : "0") + ");";
	MAYA_RETURN_IF_FAIL(MGlobal::executeCommand(command, false, false), false);

	return true;
}

/**
	Update the parameters panel based on the current selection
	
	@author Dacre Denny
	@return true if successful, false otherwise
*/
bool VGUI::Refresh::SelectionParameters() {

	MString parameter;

	if(!VSyncViewer::Selection::IsValid()) {
	
		parameter = "";
	}
	else {

		if(!VUtil::GetObjectName(VSyncViewer::Selection::Mesh, parameter))
			return false;
	}
		
	MString command = ("UpdateSelectionParametersPanel(\"" + parameter + "\");");
	MAYA_RETURN_IF_FAIL(MGlobal::executeCommand(command, false, false), false);
	return true;
}

/**
	Update the current select information panel
	
	@author Dacre Denny
	@return true if successful, false otherwise
*/
bool VGUI::Refresh::CurrentSelection() {
	
	MString parameter;

	if(!VSyncViewer::Selection::IsValid()) {
	
		parameter = "";
	}
	else {

		if(!VUtil::GetObjectName(VSyncViewer::Selection::Mesh, parameter))
			return false;
	}

	MString command = ("UpdateCurrentSelectionPanel(\"" + parameter + "\");");
	MAYA_RETURN_IF_FAIL(MGlobal::executeCommand(command, false, false), false);
	return true;
}

bool VGUI::Refresh::ProceduralPopulation() {
	
	MString parameterString;

	if(VSyncViewer::Selection::IsValid()) {

		MStatus result;
		MFnDagNode meshDN(VSyncViewer::Selection::Mesh, &result);
		MAYA_RETURN_IF_FAIL(result, false);
		
		parameterString = meshDN.name();
	}
	else {

		parameterString = "";
	}

	MString commandString = "UpdateInstancingPanel(" + MAYA_STRINGSTRING( parameterString ) + ");";
	MAYA_RETURN_IF_FAIL(MGlobal::executeCommand(commandString, false, false), false);
	return true;
}